use std::path::PathBuf;
use crate::error::{DownloadError, DownloadResult};

/// 下载配置
#[derive(Debug, Clone)]
pub struct DownloadConfig {
    pub concurrent: usize,
    pub retry_count: usize,
    pub buffer_size: usize,
    pub temp_dir: PathBuf,
    pub proxy_url: Option<String>,
    pub timeout_secs: u64,
}

impl Default for DownloadConfig {
    fn default() -> Self {
        Self {
            concurrent: 16,
            retry_count: 5,
            buffer_size: 1024 * 1024, // 1MB
            temp_dir: PathBuf::from("temp"),
            proxy_url: None,
            timeout_secs: 30,
        }
    }
}

/// 配置建造者模式
pub struct DownloadConfigBuilder {
    config: DownloadConfig,
}

impl DownloadConfigBuilder {
    pub fn new() -> Self {
        Self {
            config: DownloadConfig::default(),
        }
    }

    pub fn concurrent(mut self, concurrent: usize) -> Self {
        if concurrent == 0 {
            self.config.concurrent = 1;
        } else {
            self.config.concurrent = concurrent;
        }
        self
    }

    pub fn retry_count(mut self, retry_count: usize) -> Self {
        self.config.retry_count = retry_count;
        self
    }

    pub fn buffer_size(mut self, buffer_size: usize) -> Self {
        if buffer_size == 0 {
            self.config.buffer_size = 1024 * 1024; // 默认 1MB
        } else {
            self.config.buffer_size = buffer_size;
        }
        self
    }

    pub fn temp_dir<P: Into<PathBuf>>(mut self, temp_dir: P) -> Self {
        self.config.temp_dir = temp_dir.into();
        self
    }

    pub fn proxy_url<S: Into<String>>(mut self, proxy_url: Option<S>) -> Self {
        self.config.proxy_url = proxy_url.map(|s| s.into());
        self
    }

    pub fn timeout_secs(mut self, timeout_secs: u64) -> Self {
        self.config.timeout_secs = timeout_secs;
        self
    }

    pub fn build(self) -> DownloadResult<DownloadConfig> {
        self.validate()?;
        Ok(self.config)
    }

    fn validate(&self) -> DownloadResult<()> {
        if self.config.concurrent == 0 {
            return Err(DownloadError::Config("并发数不能为0".to_string()));
        }
        
        if self.config.buffer_size == 0 {
            return Err(DownloadError::Config("缓冲区大小不能为0".to_string()));
        }
        
        if self.config.timeout_secs == 0 {
            return Err(DownloadError::Config("超时时间不能为0".to_string()));
        }
        
        Ok(())
    }
}

impl Default for DownloadConfigBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::PathBuf;

    #[test]
    fn test_download_config_default() {
        let config = DownloadConfig::default();
        
        assert_eq!(config.concurrent, 16); // 符合用户偏好的默认16个并发
        assert_eq!(config.retry_count, 5); // 符合项目规范的5次重试
        assert_eq!(config.buffer_size, 1024 * 1024); // 1MB缓存
        assert_eq!(config.temp_dir, PathBuf::from("temp"));
        assert_eq!(config.proxy_url, None);
        assert_eq!(config.timeout_secs, 30);
    }

    #[test]
    fn test_download_config_builder_default() {
        let builder = DownloadConfigBuilder::new();
        let config = builder.build().unwrap();
        
        // 验证默认值
        assert_eq!(config.concurrent, 16);
        assert_eq!(config.retry_count, 5);
        assert_eq!(config.buffer_size, 1024 * 1024);
        assert_eq!(config.temp_dir, PathBuf::from("temp"));
        assert_eq!(config.proxy_url, None);
        assert_eq!(config.timeout_secs, 30);
    }

    #[test]
    fn test_download_config_builder_chain() {
        let config = DownloadConfigBuilder::new()
            .concurrent(32)
            .retry_count(10)
            .buffer_size(2 * 1024 * 1024)
            .temp_dir("/tmp/downloads")
            .proxy_url(Some("socks5://127.0.0.1:1080"))
            .timeout_secs(60)
            .build()
            .unwrap();
        
        assert_eq!(config.concurrent, 32);
        assert_eq!(config.retry_count, 10);
        assert_eq!(config.buffer_size, 2 * 1024 * 1024);
        assert_eq!(config.temp_dir, PathBuf::from("/tmp/downloads"));
        assert_eq!(config.proxy_url, Some("socks5://127.0.0.1:1080".to_string()));
        assert_eq!(config.timeout_secs, 60);
    }

    #[test]
    fn test_download_config_builder_zero_concurrent() {
        // 测试并发数为0时自动调整为1
        let config = DownloadConfigBuilder::new()
            .concurrent(0)
            .build()
            .unwrap();
        
        assert_eq!(config.concurrent, 1);
    }

    #[test]
    fn test_download_config_builder_zero_buffer_size() {
        // 测试缓冲区大小为0时自动调整为默认值
        let config = DownloadConfigBuilder::new()
            .buffer_size(0)
            .build()
            .unwrap();
        
        assert_eq!(config.buffer_size, 1024 * 1024);
    }

    #[test]
    fn test_download_config_builder_validation_errors() {
        // 测试验证错误 - 并发数为0（应该被自动修正，不会出错）
        let result = DownloadConfigBuilder::new()
            .concurrent(0)
            .build();
        assert!(result.is_ok());
        
        // 测试验证错误 - 缓冲区大小为0（应该被自动修正，不会出错）
        let result = DownloadConfigBuilder::new()
            .buffer_size(0)
            .build();
        assert!(result.is_ok());
        
        // 测试验证错误 - 超时时间为0
        let result = DownloadConfigBuilder::new()
            .timeout_secs(0)
            .build();
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), crate::error::DownloadError::Config(_)));
    }

    #[test]
    fn test_download_config_builder_proxy_variants() {
        // 测试不同的代理配置
        let configs = vec![
            (None, None),
            (Some("socks5://127.0.0.1:1080"), Some("socks5://127.0.0.1:1080".to_string())),
            (Some("socks5://proxy.example.com:8080"), Some("socks5://proxy.example.com:8080".to_string())),
        ];
        
        for (input, expected) in configs {
            let config = DownloadConfigBuilder::new()
                .proxy_url(input)
                .build()
                .unwrap();
            
            assert_eq!(config.proxy_url, expected);
        }
    }

    #[test]
    fn test_download_config_builder_extreme_values() {
        // 测试极端值
        let config = DownloadConfigBuilder::new()
            .concurrent(1000) // 非常大的并发数
            .retry_count(100) // 非常多的重试次数
            .buffer_size(100 * 1024 * 1024) // 100MB缓冲区
            .timeout_secs(3600) // 1小时超时
            .build()
            .unwrap();
        
        assert_eq!(config.concurrent, 1000);
        assert_eq!(config.retry_count, 100);
        assert_eq!(config.buffer_size, 100 * 1024 * 1024);
        assert_eq!(config.timeout_secs, 3600);
    }

    #[test]
    fn test_download_config_clone() {
        let original = DownloadConfig::default();
        let cloned = original.clone();
        
        assert_eq!(original.concurrent, cloned.concurrent);
        assert_eq!(original.retry_count, cloned.retry_count);
        assert_eq!(original.buffer_size, cloned.buffer_size);
        assert_eq!(original.temp_dir, cloned.temp_dir);
        assert_eq!(original.proxy_url, cloned.proxy_url);
        assert_eq!(original.timeout_secs, cloned.timeout_secs);
    }

    #[test]
    fn test_download_config_debug() {
        let config = DownloadConfig::default();
        let debug_str = format!("{config:?}");
        
        // 确保Debug输出包含关键信息
        assert!(debug_str.contains("concurrent"));
        assert!(debug_str.contains("retry_count"));
        assert!(debug_str.contains("buffer_size"));
        assert!(debug_str.contains("temp_dir"));
    }

    #[test]
    fn test_download_config_builder_default_trait() {
        let builder1 = DownloadConfigBuilder::new();
        let builder2 = DownloadConfigBuilder::default();
        
        let config1 = builder1.build().unwrap();
        let config2 = builder2.build().unwrap();
        
        assert_eq!(config1.concurrent, config2.concurrent);
        assert_eq!(config1.retry_count, config2.retry_count);
        assert_eq!(config1.buffer_size, config2.buffer_size);
    }
}